<?php

/**
 * Базовый класс форм, которые в целях безопасности содержат элементы для ввода
 * ответов на секретные вопросы.
 *
 */
abstract class Security_Action_Secured_Abstract extends Kernel_Action_Form {

    /**
     * Флаг, указывающий, что в форме может только редактироваться существующая
     * запись - т.к. отвечать на вопросы, естественно, может только залогиненный
     * пользователь.
     *
     * @var boolean
     */
    protected $_update_only = true;

    /**
     * Флаг ошибки ввода ответа на секретный вопрос.
     *
     * @var boolean
     */
    public $_question_error = false;

    /**
     * Конструктор
     *
     * @param   array   $params
     */
    public function __construct($params = array()) 
    {
        // устанавливаем идентификатор редактируемой записи
        $params['id'] = $this->_defineId();
        
        parent::__construct($params);
    }

    /**
     * Добавляет в форму элементы для ввода ответов на секретные вопросы.
     *
     * @param   array   $params
     */
    protected function _addQuestions() 
    {
        foreach (Security_Utils_Subject::getQuestions($this->id) as $position => $pair) {
            
            list($question, $answer) = array_values($pair);
            $this->_addElement('answers[' . $position . ']', 'string', array(
                'caption'  => $question,
                'required' => true,
                'validators' => array(
                    array('Kernel_Validator_Equals', array(
                        'value' => $answer,
                        'message' => 'VALIDATION_ERROR_SECRET_ANSWER',
                    )),
                ),
            ));
        }
    }

    /**
     * Проверяет значение указанного поля (с учетом того, что оно непустое).
     *
     * @param   string $name
     * @return  boolean
     */
    protected function _validateValue($name) 
    {
        // если произошла ошибка значения (т.е. поле было заполнено, непустое)
        if ((!$result = parent::_validateValue($name))
            // и это поле ввода ответа
            && 0 === strpos($name, 'answers')) {
            // пиздец, чувак, ты попал!
            $this->_question_error = true;
        }

        return $result;
    }

    /**
     * Выполняет проверку данных формы.
     *
     * @return  boolean
     */
    protected function _validate() 
    {
        if (false !== ($remain = Security_Utils_BruteForce::banned($this->id, Security_Utils_BruteForce::A_QUESTIONS))) {
            $this->_error(__('AUTHORIZE_BANNED', $remain));
            return;
        }

        // сбрасываем значение флага
        $this->_question_error = false;

        // если в форме есть ошибки
        if (!$result = parent::_validate()) {
            // если это ошибка ввода ответа на вопрос
            if ($this->_question_error) {
                // регистрируем ошибку
                Security_Utils_BruteForce::register($this->id, Security_Utils_BruteForce::A_QUESTIONS);
            }
        } else {
            // сбрасываем зарегистрированные ошибки
            Security_Utils_BruteForce::clear($this->id, Security_Utils_BruteForce::A_QUESTIONS);
        }

        return $result;
    }

    /**
     * Устанавливает идентификатор редактируемой записи.
     *
     */
    protected function _defineId() 
    {
        // выставляем идентификатор формы в значение в идентификатора учетной
        // записи текущего пользователя
        return Security_Session::getSubjectId();
    }
}
